package cn.lingque.redis;
import cn.lingque.base.LQKey;
import cn.lingque.mq.exten.*;
import cn.lingque.redis.exten.*;
import io.lettuce.core.api.sync.RedisCommands;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Supplier;

/**
 * <p>
 * redis 增强,出于安全考虑，不使用lua脚本
 * </p>
 *
 * @author zlm
 * @date 2022/8/8
 * @since 1.0
 */
@Slf4j
public class LingQueRedis extends BaseOpt{


    public ValueOpt ofValue(){
        return new ValueOpt(this);
    }

    public SetOpt ofSet(){
        return new SetOpt(this);
    }
    public SortedSetOpt ofZSet(){
        return new SortedSetOpt(this);
    }
    public HashOpt ofHash(){
        return new HashOpt(this);
    }
    public GeoOpt ofGeo(){
        return new GeoOpt(this);
    }

    public ListOpt ofList(){
        return new ListOpt(this);
    }

    /**
     * 获取统一消息队列实例
     * @return 统一消息队列
     */
    public LQUnifiedQueue ofUnifiedQueue(){
        return new LQUnifiedQueue(this);
    }

    /**
     * 获取统一消息队列实例
     * @return 统一消息队列
     */
    public LQStreamUnifiedQueue ofStreamUnifiedQueue(){
        return new LQStreamUnifiedQueue<>(this);
    }


    public LockOpt ofLock(){
        return new LockOpt(this);
    }

    /**>:--------------------------------------------构建-----------------------------------------------**/

    public static  LingQueRedis ofKey(LQKey key, Object... params) {
        if (null == key) {
            throw new RuntimeException("key 不允许为空");
        }
        LingQueRedis plus = new LingQueRedis();
        plus.key = key.buildKey(params);
        plus.ttl = key.getTtl();
        return plus;
    }


    /**
     * 关联一个key，基于普通String构建
     * @param key
     * @return
     */
    public static LingQueRedis ofKey(String key, Long ttl) {
        LingQueRedis plus = new LingQueRedis();
        plus.key = key;
        plus.ttl = ttl;
        return plus;
    }



    /**执行后重制缓存*/
    public <T>T run(Supplier<T> runner){
        try {
            return runner.get();
        }finally {
            resetTTL();
        }
    }

    /**
     * 获取原始执行器
     * @param exec
     * @return
     * @param <T>
     */
    public <T>T exec(BaseExec<T> exec){
       return JedisProxy.execBaseWithRetry((commands)->{
            return exec.exec(commands,key,ttl,this);
        },10);
    }

    /**
     * 获取原始执行器-需要自动重置时间的时候可以使用
     * @param exec
     * @return
     * @param <T>
     */
    public <T>T execWithRunner(BaseExec<T> exec){
       return JedisProxy.execBaseWithRetry((commands)->run(() -> exec.exec(commands, key, ttl, this)),10);
    }


    public static interface BaseExec<T>{
        <T> T exec(RedisCommands<String, String> commands, String key, long ttl, LingQueRedis lingQueRedis);
    }

    public static interface BaseSimpleExec{
        Object exec(RedisCommands<String, String> commands);
    }

    /**
     * 获取原始执行器
     * @param exec
     * @return
     */
    public Object execBase(BaseSimpleExec exec){
        return JedisProxy.execBaseWithRetry(exec,10);
    }

    /**
     * 获取原始执行器（带重试机制）
     * @param exec 执行器
     * @param maxRetries 最大重试次数
     * @return 执行结果
     */
    public Object execBaseWithRetry(BaseSimpleExec exec, int maxRetries) {
        return JedisProxy.execBaseWithRetry(exec, maxRetries);
    }

    /**
     * 获取原始执行器（带重试机制，默认3次重试）
     * @param exec 执行器
     * @return 执行结果
     */
    public Object execBaseWithRetry(BaseSimpleExec exec) {
        return execBaseWithRetry(exec, 3);
    }
}
